<template>
    <div ref="container" class="model-container"></div>
</template>

<script>
import * as THREE from "three"
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js"
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"

export default {
    name: "FBXViewer",
    props: {
        modelUrl: {
            type: String,
            required: true
        },
        backgroundColor: {
            type: String,
            default: "#f0f0f0"
        }
    },
    data() {
        return {
            scene: null,
            camera: null,
            renderer: null,
            controls: null,
            mixer: null
        }
    },
    mounted() {
        this.initThreeJS()
        this.loadFBXModel()
        this.animate()
    },
    beforeUnmount() {
        this.cleanUp()
    },
    methods: {
        initThreeJS() {
            // 1. 创建场景
            this.scene = new THREE.Scene()
            this.scene.background = new THREE.Color(this.backgroundColor)

            // 2. 创建相机
            const container = this.$refs.container
            const width = container.clientWidth
            const height = container.clientHeight

            this.camera = new THREE.PerspectiveCamera(
                45,
                width / height,
                0.1,
                1000
            )
            this.camera.position.set(0, 0, 5)

            // 3. 创建渲染器
            this.renderer = new THREE.WebGLRenderer({ antialias: true })
            this.renderer.setSize(width, height)
            this.renderer.setPixelRatio(window.devicePixelRatio)
            this.renderer.shadowMap.enabled = true
            container.appendChild(this.renderer.domElement)

            // 4. 添加控制器
            this.controls = new OrbitControls(this.camera, this.renderer.domElement)
            this.controls.enableDamping = true

            // 5. 添加光源
            const ambientLight = new THREE.AmbientLight(0x404040)
            this.scene.add(ambientLight)

            const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
            directionalLight.position.set(1, 1, 1)
            directionalLight.castShadow = true
            this.scene.add(directionalLight)

            // 窗口大小调整
            window.addEventListener("resize", this.onWindowResize)
        },

        loadFBXModel() {
            const loader = new FBXLoader()

            loader.load(
                this.modelUrl,
                (fbx) => {
                    // 缩放模型到合适大小
                    fbx.scale.setScalar(0.01)

                    // 居中模型
                    const box = new THREE.Box3().setFromObject(fbx)
                    const center = box.getCenter(new THREE.Vector3())
                    fbx.position.sub(center)

                    this.scene.add(fbx)

                    // 处理动画（如果有）
                    if (fbx.animations.length > 0) {
                        this.mixer = new THREE.AnimationMixer(fbx)
                        const action = this.mixer.clipAction(fbx.animations[0])
                        action.play()
                    }
                },
                (xhr) => {
                    console.log((xhr.loaded / xhr.total * 100) + "% loaded")
                },
                (error) => {
                    console.error("Error loading FBX model:", error)
                }
            )
        },

        animate() {
            requestAnimationFrame(animate)

            // 确保先更新所有矩阵
            scene.traverse(obj => {
                if (obj.isObject3D) {
                    obj.updateMatrixWorld(true) // 强制更新
                }
            })

            // 然后再渲染
            renderer.render(scene, camera)
        },

        onWindowResize() {
            const container = this.$refs.container
            const width = container.clientWidth
            const height = container.clientHeight

            this.camera.aspect = width / height
            this.camera.updateProjectionMatrix()
            this.renderer.setSize(width, height)
        },

        cleanUp() {
            window.removeEventListener("resize", this.onWindowResize)
            this.$refs.container.removeChild(this.renderer.domElement)
        }
    }
}
</script>

<style scoped>
.model-container {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
</style>
